﻿using Adnc.Shared.ConfigModels;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using WYT.Usr.Repository.Entities;

namespace WYT.Usr.Application
{
    /// <summary>
    /// 
    /// </summary>
    //认证服务器安装：System.IdentityModel.Tokens.Jwt
    //资源服务器安装：Microsoft.AspNetCore.Authentication.JwtBearer
    public enum TokenType
    {
        /// <summary>
        /// 
        /// </summary>
        AccessToken = 1,
        /// <summary>
        /// 
        /// </summary>
        RefreshToken = 2
    }

    /// <summary>
    /// 
    /// </summary>
    public static class JwtTokenHelper
    {
        /// <summary>
        /// 创建token
        /// </summary>
        /// <param name="jwtConfig"></param>
        /// <param name="claims"></param>
        /// <param name="tokenType"></param>
        /// <returns></returns>
        public static string CreateToken(JwtConfig jwtConfig, Claim[] claims, TokenType tokenType)
        {
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.SymmetricSecurityKey));

            string issuer = jwtConfig.Issuer;
            string audience = tokenType.Equals(TokenType.AccessToken) ? jwtConfig.Audience : jwtConfig.RefreshTokenAudience;
            int expires = tokenType.Equals(TokenType.AccessToken) ? jwtConfig.Expire : jwtConfig.RefreshTokenExpire;

            var token = new JwtSecurityToken(
                issuer: issuer,
                audience: audience,
                claims: claims,
                notBefore: DateTime.Now,
                expires: DateTime.Now.AddMinutes(expires),
                signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)
            );

            var jwtAccessTokenToken = new JwtSecurityTokenHandler().WriteToken(token);
            return jwtAccessTokenToken;
        }

        /// <summary>
        /// token
        /// </summary>
        /// <param name="jwtConfig"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        public static string CreateAccessToken(JwtConfig jwtConfig, User user)
        {
            var claims = new Claim[]
            {
                new Claim(ClaimTypes.NameIdentifier, user.Account.ToString()),
                new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
                new Claim(ClaimTypes.Name, user.Nickname ?? String.Empty)
            };
            return CreateToken(jwtConfig, claims, TokenType.AccessToken);
        }

        /// <summary>
        /// 刷新token
        /// </summary>
        /// <param name="jwtConfig"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        public static string CreateRefreshToken(JwtConfig jwtConfig, User user)
        {
            var claims = new Claim[]
            {
                new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString())
            };
            return CreateToken(jwtConfig, claims, TokenType.RefreshToken);
        }
        /// <summary>
        /// 适用刷新token创建token
        /// </summary>
        /// <param name="jwtConfig"></param>
        /// <param name="user"></param>
        /// <param name="refreshTokenTxt"></param>
        /// <returns></returns>
        public static string CreateAccessToken(JwtConfig jwtConfig, User user, string refreshTokenTxt)
        {
            var token = new JwtSecurityTokenHandler().ReadJwtToken(refreshTokenTxt);
            if (token != null)
            {
                var claimAccount = token.Claims.First(x => x.Type == JwtRegisteredClaimNames.Sub).Value;

                if (user != null && user.Id == long.Parse(claimAccount))
                {
                    return CreateAccessToken(jwtConfig, user);
                }
            }
            return string.Empty;
        }

        /// <summary>
        /// 获取token中用户ID
        /// </summary>
        /// <param name="TokenTxt"></param>
        /// <returns></returns>
        public static long GetUserId(string TokenTxt)
        {
            var token = new JwtSecurityTokenHandler().ReadJwtToken(TokenTxt);
            if (token != null)
            {
                var claimAccount = token.Claims.First(x => x.Type == JwtRegisteredClaimNames.Sub).Value;
                if (claimAccount.IsNull())
                    return 0;
                else
                    return long.Parse(claimAccount);
            }
            else
                return 0;
        }
    }
}